package org.yangspring.samples.mvc.simple;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceView;
import org.springframework.web.servlet.view.JstlView;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Null;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Controller
public class SimpleController {
	private static final Logger logger = LoggerFactory.getLogger(AnimalController.class);

	@Autowired
	private ServletContext servletContext;

	@RequestMapping("/simple")
	public @ResponseBody
	String simple() {
		return "Hello world!";
	}

	@RequestMapping(value = "/frankie", method = RequestMethod.GET)
	public @ResponseBody
	String homePageGET() {
		return "Frankling Yang Page [BY METHOD GET]";
	}

	/*
	@RequestMapping(value = "/frankie", method = RequestMethod.POST)
	public @ResponseBody String homePagePOST(HttpServletRequest req){
		System.logger.warn("\nhomePagePOST:\n" + req.toString());
		System.logger.warn("\npara frankie3:\n" + req.getParameter("frankie3"));
		System.logger.warn("\npara foo:\n" + req.getParameter("foo"));
		return "Frankling Yang Page [BY METHOD POST]";
	}
	*/

	@RequestMapping(value = "/frankie", method = RequestMethod.POST)
	public @ResponseBody
	String homePagePOST(@ModelAttribute PojoFrankie pojo) {
		logger.warn("\n\t\thomePagePOST:\t\t" + pojo.getFoo());
		logger.warn("\n\t\thomePagePOST:\t\t" + pojo.getFrankie());
		return "Frankling Yang Page [BY METHOD POST]";
	}

	@RequestMapping(value = "/frankie2", method = RequestMethod.POST)
	public @ResponseBody
	String homePagePOST2(@ModelAttribute("pojo") PojoFrankie pojo) {
		logger.warn("\n\t\t2 homePagePOST:\t\t" + pojo.getFoo());
		logger.warn("\n\t\t2 homePagePOST:\t\t" + pojo.getFrankie());
		return "Frankling Yang Page [BY METHOD POST]";
	}

	/*@RequestMapping(value = "/frankie2", method = RequestMethod.POST)
	public @ResponseBody String homePagePOST2(HttpServletRequest req){
		System.logger.warn("Frankie2 Post: " + req.getParameterMap().toString());
		return "Frankling Yang Page [BY METHOD POST]";
	}*/

	@RequestMapping(value = "/frankie5", method = RequestMethod.POST)
	public @ResponseBody
	String homePagePOST5(@ModelAttribute("foo") PojoFrankie pojo) {
		logger.warn("\n\t\t5 homePagePOST:\t\t" + pojo.getFoo());
		logger.warn("\n\t\t5 homePagePOST:\t\t" + pojo.getFrankie());
		return "Frankling Yang Page [BY METHOD POST]";
	}


	@RequestMapping(value = "/svltctrl1", method = RequestMethod.GET)
	public @ResponseBody
	String svltctrl1() {

		WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
		ServletContext servletContext2 = wac.getServletContext();

//		context.getContextPath();
		System.out.println("@Autowired注入获取ServletConext的内容：");
		Enumeration<String> c = servletContext.getAttributeNames();
		while (c.hasMoreElements()) {
			String s = c.nextElement();

			System.out.println("\n\t\tServletContext 1 :\t\t" + s.toString() + "\t:\t" + servletContext.getAttribute(s));
//			logger.warn("\n\t\tServletContext 1 :\t\t" + s.toString());
		}

//		context.getContextPath();
		System.out.println("ContextLoader提供方法getCurrentWebApplicationContext获取ServletConext的内容：");
		Enumeration<String> c2 = servletContext2.getAttributeNames();
		while (c2.hasMoreElements()) {
			String s = c2.nextElement();
			System.out.println("\n\t\tServletContext 2 :\t\t" + s.toString() + "\t:\t" + servletContext.getAttribute(s));
//			logger.warn("\n\t\tServletContext 2 :\t\t" + s.toString());
		}
		return "svltctrl1" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
	}

	@RequestMapping(value = "/svltctrl2", method = RequestMethod.GET)
	public /*@ResponseBody*/ String svltctrl2(HttpServletRequest request) {
		System.out.println("HttpServletRequest获取ServletConext的内容：");

		ServletContext context = request.getSession().getServletContext();
		Enumeration<String> c = context.getAttributeNames();

//		context.getContextPath();
		while (c.hasMoreElements()) {
			String s = c.nextElement();
			System.out.println("\n\t\tServletContext 2 :\t\t" + s.toString() + "\t:\t" + servletContext.getAttribute(s));
//			logger.warn("\n\t\tServletContext 2 :\t\t" + s.toString());
		}
//		return "svltctrl2";
		//	View 实现类名称为 FrankieView，但是这里返回时，首字母要小写，TMD！
		return "frankieView";
	}

	@RequestMapping(value = "/svltctrl3", method = RequestMethod.GET)
	public /*@ResponseBody*/ Object svltctrl3(HttpServletRequest request) {
//		return "svltctrl3";
		//	View 实现类名称为 FrankieView，但是这里返回时，首字母要小写，TMD！
//		return "frankieView";
		return new ModelAndView("frankieView");
	}

	@RequestMapping(value = "/svltctrl4", method = RequestMethod.GET)
	public /*@ResponseBody*/ ModelAndView svltctrl4(HttpServletRequest request) {
//		return "svltctrl4";
		//	View 实现类名称为 FrankieView，但是这里返回时，首字母要小写，TMD！
//		return "frankieView";
		return new ModelAndView("frankieView");
	}

	@RequestMapping("/testModelAndViewVoid")
	public void testModelAndViewVoid() {
		/* 返回值为void时
		 * view：前端页面请求的路径+InternalResourceViewResolver
		 * 添加的前缀和后缀：如"WEB-INF/views/springmvc/testModelAndViewVoid.jsp"
		 *
		 * model: Map或ModelAndView*/
		System.out.println("\nI\nam\nComming\ntestModelAndViewVoid\n");
	}

	@RequestMapping("yang12/testModelAndViewVoid")
	public void test12ModelAndViewVoid() {
		/* 返回值为void时
		 * view：前端页面请求的路径+InternalResourceViewResolver
		 * 添加的前缀和后缀：如"WEB-INF/views/springmvc/testModelAndViewVoid.jsp"
		 *
		 * model: Map或ModelAndView*/
		System.out.println("\nI\nam\nComming12\ntestModelAndViewVoid\n");
	}

	/**
	 * SpringMVC在调用方法前会创建一个隐藏的模型对象作为模型数据在存储容器。
	 * 如果方法的入参 为Map或Model类型，SpringMVC会将隐藏的模型的引用传递给这些入参。
	 * 在该方法中我们可以往访问到该模型中的所有数据也可以往模型中添加数据
	 */
	@RequestMapping("/testModelAndViewMap")
	public Map<String, Object> testModelAndViewMap(Map<String, Object> map) {
		/* 返回值是Map类型时
		 * view：前端页面请求的路径+InternalResourceViewResolver
		 * 添加的前缀和后缀：如"WEB-INF/views/springmvc/testModelAndViewMap.jsp
		 *
		 * model:Map(同时也会被添加到request域中);
		 * */
		System.out.println("\nI\nam\nComming\ntestModelAndViewMap\n");
		map.put("map-obj", new Object());
		return map;
	}

	@RequestMapping("/testModelAndViewObject")
	public Object testModelAndViewObject() {
		/* 返回值是一个对象类型时
		 * view：前端页面请求的路径+InternalResourceViewResolver
		 * 添加的前缀和后缀：如"WEB-INF/views/springmvc/testModelAndViewObject.jsp
		 *
		 * model:Object(同时也会被添加到request域中);
		 * */

		System.out.println("\nI\nam\nComming\ntestModelAndViewObject\n");
//		return new Object();
		return new ModelAndViewObject();
	}

	@RequestMapping("/testModelAndViewObjectb")
	public Object testModelAndViewObjectb(){
		System.out.println("\nI\nam\nComming\ntestModelAndViewObjectb\n");
//		return new Object();
		return new ModelAndViewObject();
	}

	@RequestMapping("/testModelAndViewObject5")
	public Object testModelAndViewObject5(){
		System.out.println("\nI\nam\nComming12\ntestModelAndViewObject5\n");
//		return new ModelAndViewObject();
		return "yang12/testModelAndViewObject5";
	}

	@RequestMapping("/testModelAndViewObject5b")
	public String testModelAndViewObject5b(){
		System.out.println("\nI\nam\nComming12\ntestModelAndViewObject5b\n");
//		return new ModelAndViewObject();
		return "yang12/testModelAndViewObject5";
	}

	@RequestMapping("/testModelAndViewObject5c")
	public ModelAndView testModelAndViewObject5c(){
		System.out.println("\nI\nam\nComming12\ntestModelAndViewObject5c\n");
//		return new ModelAndViewObject();
//		return "yang12/testModelAndViewObject5";
		return new ModelAndView("yang12/testModelAndViewObject5");
	}

	@RequestMapping("yang12/testModelAndViewObject6")
	public Object testModelAndViewObject6(){
		System.out.println("\nI\nam\nComming12\ntestModelAndViewObject6\n");
//		return new ModelAndViewObject();
		return "yang12/testModelAndViewObject6";
	}

	@RequestMapping("yang12/testModelAndViewObject7")
	public @ResponseBody Object testModelAndViewObject7(){
		System.out.println("\nI\nam\nComming12\ntestModelAndViewObject7\n");
//		return "testModelAndViewObject7";
		return new ModelAndViewObject();
	}

	@RequestMapping("yang12/testModelAndViewObject77")
	public @ResponseBody Object testModelAndViewObject77(){
		System.out.println("\nI\nam\nComming12\ntestModelAndViewObject77\n");
		return "testModelAndViewObject77";
	}

	@RequestMapping("yang12/testModelAndViewObject78")
	public @ResponseBody Object testModelAndViewObject78(){
		System.out.println("\nI\nam\nComming12\ntestModelAndViewObject78\n");
		return new ModelAndViewObject();
	}

	@RequestMapping("/testModelAndViewObject2")
	public @ResponseBody Object testModelAndViewObject2(){
		System.out.println("\nI\nam\nComming\ntestModelAndViewObject2\n");
		return new ModelAndViewObject();
	}

	@RequestMapping("/testModelAndViewObject3")
	@ResponseBody
	public Object testModelAndViewObject3(){
		System.out.println("\nI\nam\nComming\ntestModelAndViewObject3\n");
		return new ModelAndViewObject();
	}

    @RequestMapping("yang12/testModelAndViewObject3")
    @ResponseBody
    public Object tes12tModelAndViewObject3(){
        System.out.println("\nI\nam\nComming12\ntestModelAndViewObject3\n");
        return new ModelAndViewObject();
    }

	@RequestMapping("/testModelAndViewObject4")
	@ResponseBody
	public Map<String, Object> testModelAndViewObject4(){
		System.out.println("\nI\nam\nComming\ntestModelAndViewObject4\n");
		Map map = new HashMap();
		map.put("name", "Frankie Yang");
		map.put("gender", "female");
		map.put("age", 23);
		map.put("asset", 572000000);
		return map;
	}

	class ModelAndViewObject {
		private String name;
		private boolean marriage;
		private int age;
		private String gender;
		private String career;

		public ModelAndViewObject(){
			this.name = "frankie Yang";
			this.age = 22;
			this.gender = "male";
			this.marriage = true;
			this.career = "Big Data";
		}

		public boolean isMarriage() {
			return marriage;
		}
		public void setMarriage(boolean marriage) {
			this.marriage = marriage;
		}

		public int getAge() {
			return age;
		}
		public void setAge(int age) {
			this.age = age;
		}

		public String getCareer() {
			return career;
		}
		public void setCareer(String career) {
			this.career = career;
		}

		public String getGender() {
			return gender;
		}
		public void setGender(String gender) {
			this.gender = gender;
		}

		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}

		@Override
		public String toString() {
			return super.toString();
		}
	}

	@RequestMapping(value = "/frankie6", method = {RequestMethod.POST, RequestMethod.GET})
	public @ResponseBody String homePagePOST6(HttpServletRequest request, PojoFrankie pojo){
		System.out.println("\n\t\t5 homePagePOST:\t\t" + pojo.getFoo());
		System.out.println("\n\t\t5 homePagePOST:\t\t" + pojo.getFrankie());

		System.out.println("\n\n\n");

		/*****	1	***/
		WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
		System.out.println(
				"\n\t\t[LOCATOR_FACTORY_SELECTOR_PARAM]\t\t" + ContextLoader.LOCATOR_FACTORY_SELECTOR_PARAM +
				"\n\t\t[LOCATOR_FACTORY_KEY_PARAM]\t\t" + ContextLoader.LOCATOR_FACTORY_KEY_PARAM +
				"\n\t\t[CONFIG_LOCATION_PARAM]\t\t" + ContextLoader.CONFIG_LOCATION_PARAM +
				"\n\t\t[CONTEXT_CLASS_PARAM]\t\t" + ContextLoader.CONTEXT_CLASS_PARAM +
				"\n\t\t[CONTEXT_ID_PARAM]\t\t" + ContextLoader.CONTEXT_ID_PARAM +
				"\n\t\t[CONTEXT_INITIALIZER_CLASSES_PARAM]\t\t" + ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM +
				"\n\t\t[GLOBAL_INITIALIZER_CLASSES_PARAM]\t\t" + ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM
		);

		if (wac != null) {
			System.out.println(
					"\n\t\tWAC getClassLoader\t\t" + wac.getClassLoader() +
					"\n\t\tWAC getServletContext\t\t" + wac.getServletContext() +
					"\n\t\tWAC getDisplayName\t\t" + wac.getDisplayName() +
					"\n\t\tWAC getBeanDefinitionNames\t\t" + wac.getBeanDefinitionNames().toString() +
					"\n\t\tWAC getApplicationName\t\t" + wac.getApplicationName() +
					"\n\t\tWAC getBeanDefinitionCount\t\t" + wac.getBeanDefinitionCount() +
					"\n\t\tWAC getEnvironment\t\t" + wac.getEnvironment()
			);

			ClassLoader cldr = wac.getClassLoader();
			if (cldr != null) {
				System.out.println(
						"\n\t\tWAC-getClassLoader getParent\t\t" + cldr.getParent() +
                        "\n\t\tWAC-getClassLoader getClass\t\t" + cldr.getClass()
				);
			} else {
				System.out.println("\n\t\tContextLoader.getCurrentWebApplicationContext(); getClassLoader() nothing!");
			}

			ServletContext sc = wac.getServletContext();
			if (sc != null) {
				System.out.println(
						"\n\t\tWAC getServletContext getServletContextName\t\t" + sc.getServletContextName() +
						"\n\t\tWAC getServletContext getClassLoader\t\t" + sc.getClassLoader() +
						"\n\t\tWAC getServletContext getClass\t\t" + sc.getClass() +
						"\n\t\tWAC getServletContext getAttributeNames\t\t" + sc.getAttributeNames().toString() +
						"\n\t\tWAC getServletContext getContextPath\t\t" + sc.getContextPath() +
//								"\n\t\tgetServletContext getInitParameterNames" + sc.getInitParameterNames() +
						"\n\t\tWAC getServletContext getInitParameterNames\t\t" + sc.getInitParameterNames().toString() +
						"\n\t\tWAC getServletContext getServerInfo\t\t" + sc.getServerInfo() +
						"\n\t\tWAC getServletContext getSessionCookieConfig\t\t" + sc.getSessionCookieConfig()
				);

				Enumeration<String> es = sc.getAttributeNames();
				System.out.println("\n\t\t[Every Attribute oF ServletContext]");
				while (es.hasMoreElements()) {
					String attr = es.nextElement().toString();
					/*System.out.println(
							"\t\t\t\t[Every Attribute oF ServletContext] getAttributeNames\t\t" + *//*es.nextElement().toString()*//* attr
					);
					System.out.println(
							"\t\t\t\t\t\t[Every Attribute oF ServletContext getAttribute]\t\t" + sc.getAttribute(attr)
					);*/
					System.out.println(
							"\n\t\t" +
									attr +
									"\n\t\t" +
									sc.getAttribute(attr)
					);
				}

//				sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE).toString();

			} else {
				System.out.println("\n\t\tContextLoader.getCurrentWebApplicationContext(); getServletContext() nothing!");
			}

			Environment env = wac.getEnvironment();
			if (env != null) {
				System.out.println(
						"\n\t\tWAC-getEnvironment getActiveProfiles\t\t" + env.getActiveProfiles().toString() +
								"\n\t\tWAC-getEnvironment getDefaultProfiles\t\t" + env.getDefaultProfiles().toString()
				);
			} else {
				System.out.println("ContextLoader.getCurrentWebApplicationContext(); getServletContext() nothing!");
			}

			System.out.println("\n\n");
			ApplicationContext ac = wac.getParent();
			if (ac != null) {
				System.out.println(
						"\n\t\tWAC-getParent getApplicationName\t\t" + ac.getApplicationName() +
								"\n\t\tWAC-getParent getDisplayName\t\t" + ac.getDisplayName() +
								"\n\t\tWAC-getParent getParent\t\t" + ac.getParent() +
								"\n\t\tWAC-getParent getBeanDefinitionNames\t\t" + ac.getBeanDefinitionNames() +
								"\n\t\tWAC-getParent getEnvironment\t\t" + ac.getEnvironment() +
								"\n\t\tWAC-getParent getClassLoader\t\t" + ac.getClassLoader() +
								"\n\t\tWAC-getParent getBeanDefinitionCount\t\t" + ac.getBeanDefinitionCount() +
								"\n\t\tWAC-getParent getParentBeanFactory\t\t" + ac.getParentBeanFactory()
				);
			} else {
				System.out.println("\n\t\twac.getParent() get nothing !");
			}

			BeanFactory bf = wac.getParentBeanFactory();
			if (bf != null) {
				System.out.println(
						"\n\t\tWAC-BF getClass\t\t" + bf.getClass()
				);

				System.out.println("\n\n");
			} else {
				System.out.println("\n\t\twac.getParentBeanFactory() get nothing ...");
			}
		} else {
			System.out.println("\n\t\tContextLoader.getCurrentWebApplicationContext() nothing !!");
		}

		/*****	2	***/
		RequestAttributes reqAttrs = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes reqAttrs2 = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
		System.out.println(
				"\n\t\t[(ServletRequestAttributes)RequestContextHolder.getRequestAttributes()]\t\t" + reqAttrs2.getRequest().toString() +
				"\n\t\t[(ServletRequestAttributes)RequestContextHolder.getRequestAttributes()]\t\t" + reqAttrs2.getSessionId().toString()
		);

		/*****	3	***/
		WebApplicationContext wac2 = WebApplicationContextUtils.getWebApplicationContext(ContextLoader.getCurrentWebApplicationContext().getServletContext());
		System.out.println(
				"\n\t\t[WebApplicationContextUtils.getWebApplicationContext -> ContextLoader.getCurrentWebApplicationContext().getServletContext()]" + wac2.getApplicationName()
		);

//		reqAttrs2.getRequest().getServletContext();
//		ServletContext sc1 = getServletContext();
		ServletContext sc3 = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getServletContext();
		WebApplicationContext ac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(sc3);
		WebApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(sc3);

		System.out.println(
				"\n\t\t[From RequestContext, tO Request, tO ServletContext, tO WebApplicationContext]" +
				"\n\t\t((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getServletContext()\t\t" + ac1.toString() +
				"\n\t\t((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getServletContext()\t\t" + ac2.toString() +
				"\n\t\t((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getServletContext() tO getServletContext\t\t\t\t" + ac1.getServletContext().toString()
		);

		System.out.println(
				"\n\t\t[From HttpServletRequest tO ServletContext]\t\t\t\t" +
				request.getServletContext().toString()
		);

		/*
			ServletContext的获取:
				servlet.getServletContext()
				this.getServletContext()
				request.getSession().getServletContext()
				reqAttrs2.getRequest().getServletContext()
				request.getServletContext()
				ContextLoader.getCurrentWebApplicationContext().getServletContext()
		*/


		/*****	4	***/
//		RequestContextUtils

		System.out.println("\n\n\n");
		return "Frankling Yang Page [BY METHOD " + request.getMethod() + "]";
	}

}



class ModelAndViewObject {
	private String name;
	private boolean marriage;
	private int age;
	private String gender;
	private String career;

	public ModelAndViewObject(){
		this.name = "frankie Yang";
		this.age = 22;
		this.gender = "male";
		this.marriage = true;
		this.career = "Big Data";
	}

	public boolean isMarriage() {
		return marriage;
	}
	public void setMarriage(boolean marriage) {
		this.marriage = marriage;
	}

	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	public String getCareer() {
		return career;
	}
	public void setCareer(String career) {
		this.career = career;
	}

	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return super.toString();
	}


	public void werfwefwef(){

		DispatcherServlet dsptSvlt;

		ViewResolver viewrslvr;
		HandlerAdapter hdlrAdpt;

		Controller ctrl;
		JstlView jstlvw;

		InternalResourceView interRsrcV;

		ModelAndView mAv;


		HandlerAdapter hndlAdpt;

		ApplicationContext aC;

		AbstractApplicationContext absAC;

		XmlWebApplicationContext xmlWebAC;

		ConfigurableWebApplicationContext configWAC;

		DefaultResourceLoader defRsrcLdr;

	}


}



interface A {
	public void a();
}

interface B {
	public void b();
}

abstract class C {
	public void c(){
	}
}

class D extends C implements A, B {

	public void a() {
	}
	public void b() {
	}
}

class Test {
	public void testFunc() {
		A a = new D();
		a.a();
		B b = new D();
		b.b();
		C c = new D();
		c.c();
		D d = new D();
		d.a();
		d.b();
		d.c();
	}
}

